package org.springframework.aop.framework.autoproxy;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import java.util.List;

/**
 *  使用@Aspect 和 Advisor
 * @author peng_rui
 * @date 2022/7/6
 */
public class AspectAndAdvisorDemo {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("aspect1", Aspect1.class);
        context.registerBean("aConfig", AConfig.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
        // 代理对象的创建时期 (*) 位置表示代理对象的创建的时期
        // bean 创建 》 (*) 依赖注入 》 初始化 (*)

        context.refresh();

//        for (String name : context.getBeanDefinitionNames()) {
//            System.out.println(name);
//        }
        /*
            第一个重要的方法findEligibleAdvisors 找到有资格的Advisors
         */
        AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        List<Advisor> advisors = creator.findEligibleAdvisors(Target20.class, "target2");
        System.out.println("*****************");
//        for (Advisor advisor : advisors) {
//            System.out.println(advisor);
//        }

        /*
            第二个重要的方法 wrapIfNecessary 判断对象是否需要生产代理
                a 内部调用了findEligibleAdvisors 若有返回 则需要创建代理 没有则不需要创建代理
                需要创建代理 返回代理对象
                不需要则返回 对象本身
         */
        Object o = creator.wrapIfNecessary(new Target10(), "target1", "target1");
        System.out.println(o.getClass());
        Object o1 = creator.wrapIfNecessary(new Target20(), "target2", "target2");
        System.out.println(o1.getClass());

        Target10 t = (Target10) o;
        t.foo();
    }

    static class Target10 {
        public void foo() {
            System.out.println("target10 foo");
        }

        public void bar() {
            System.out.println("target10 bar");
        }
    }

    static class Target20 {
        public void star() {
            System.out.println("Target20 star");
        }
    }

    //高级切面
    @Aspect
    static class Aspect1 {
        @Before("execution(* foo())")
        public void before() {
            System.out.println("aspect1 before...");
        }

        @After("execution(* foo())")
        public void after() {
            System.out.println("aspect1 before...");
        }
    }

    //低级切面
    @Configuration
    static class AConfig {
        @Bean
        public MethodInterceptor interceptor10() {
            return invocation -> {
                System.out.println("interceptor10 before ...");
                Object proceed = invocation.proceed();
                System.out.println("interceptor10 after ...");
                return proceed;
            };
        }

        @Bean
        public Advisor advisor10(MethodInterceptor interceptor10) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* bar())");
            return new DefaultPointcutAdvisor(pointcut, interceptor10);
        }
    }


}
